package model;

import model.SimulatorConstants;
import model.components.Node;
import model.components.Server;
import model.components.SubstrateRouter;
import model.components.SubstrateSwitch;

import org.apache.commons.collections15.Factory;

/**
 * This class is a factory of SubstrateNode. It generates the elements
 * with random parameters. Ranges for randomness can be found on 
 * SimulatorConstants class
 */
public class SubstrateNodeFactory implements Factory<Node>{

	private int nodeCount;
	// Adding probability to node types
	private double serverType;
	private double switchType;
	private double routerType;
	// params range
	private int minCpu;
	private int maxCpu;
	private int minMemory;
	private int maxMemory;
	private int minDiskSpace;
	private int maxDiskSpace;
	
	public SubstrateNodeFactory() {
		super();
		nodeCount = 0;
		serverType = (double)SimulatorConstants.SERVER_DISTRIBUTION/100;
		routerType = (double)SimulatorConstants.ROUTER_DISTRIBUTION/100;
		switchType = (double)SimulatorConstants.SWITCH_DISTRIBUTION/100;
		minCpu = SimulatorConstants.MIN_CPU;
		maxCpu = SimulatorConstants.MAX_CPU;
		minMemory = SimulatorConstants.MIN_MEMORY;
		maxMemory = SimulatorConstants.MAX_MEMORY;
		minDiskSpace = SimulatorConstants.MIN_DISK;
		maxDiskSpace = SimulatorConstants.MAX_DISK;
	}
	
	/** Generate a random node **/
	public Node create() {
		Node node = null;
		int cpu;
		int memory;
		
		// Adding probability to node types
		int nodeType;
		double random = Math.random();
		if (random<=serverType) nodeType = 2;
		else if (random<=serverType+routerType) nodeType = 0;
		else nodeType = 1;
		
		switch (nodeType) {
			case 0: {
				node = new SubstrateRouter(nodeCount);
				node.setVlans(SimulatorConstants.MAX_ROUTER_VLANS);
				break;
			}
			case 1: {
				node = new SubstrateSwitch(nodeCount); 
				node.setVlans(SimulatorConstants.MAX_SWITCH_VLANS);
				// Random vlans generation
//				int vlans = SimulatorConstants.MIN_VLANS 
//							+ (int)(Math.random()*((SimulatorConstants.MAX_VLANS 
//							- SimulatorConstants.MIN_VLANS) + 1));
//				((SubstrateSwitch) node).setVlans(vlans);
				break;
			}
			case 2: {
				node = new Server(nodeCount);
				// Random diskSpace generation
				int diskSpace = minDiskSpace 
							+ (int)(Math.random()*((maxDiskSpace 
							- minDiskSpace) + 1));
				((Server) node).setDiskSpace(diskSpace);
				node.setVlans(SimulatorConstants.MAX_SERVER_VLANS);
				break;
			}
		}
		// Random cpu generation
		cpu = minCpu 
					+ (int)(Math.random()*((maxCpu 
					- minCpu) + 1));
		node.setCpu(cpu);
		// Random ram generation
		memory = minMemory 
					+ (int)(Math.random()*((maxMemory 
					- minMemory) + 1));
		node.setMemory(memory);

		nodeCount++;
		return node;
	}
	
	/** Generate a Node specified by its type **/
	public Node create(String nodeType) {
		Node node = null;
		int cpu;
		int memory;
		
		if (nodeType.equalsIgnoreCase("router")) {
			node = new SubstrateRouter(nodeCount);
			node.setVlans(SimulatorConstants.MAX_ROUTER_VLANS);
		}
		else if (nodeType.equalsIgnoreCase("switch")) {
			node = new SubstrateSwitch(nodeCount); 
			node.setVlans(SimulatorConstants.MAX_SWITCH_VLANS);
		}
		else if (nodeType.equalsIgnoreCase("server")) {
			node = new Server(nodeCount);
			// Random diskSpace generation
			int diskSpace = minDiskSpace 
						+ (int)(Math.random()*((maxDiskSpace 
						- minDiskSpace) + 1));
			((Server) node).setDiskSpace(diskSpace);
			node.setVlans(SimulatorConstants.MAX_SERVER_VLANS);
		}
		
		// Random cpu generation
		cpu = minCpu 
					+ (int)(Math.random()*((maxCpu 
					- minCpu) + 1));
		node.setCpu(cpu);
		// Random ram generation
		memory = minMemory 
					+ (int)(Math.random()*((maxMemory 
					- minMemory) + 1));
		node.setMemory(memory);

		nodeCount++;
		return node;
	}
	
	public Object getCopy() {
		SubstrateNodeFactory f = new SubstrateNodeFactory();
		f.nodeCount = this.nodeCount;
		f.serverType = this.serverType;
		f.routerType = this.routerType;
		f.switchType = this.switchType;
		f.minCpu = this.minCpu;
		f.maxCpu = this.maxCpu;
		f.minDiskSpace = this.minDiskSpace;
		f.maxDiskSpace = this.maxDiskSpace;
		f.minMemory = this.minMemory;
		f.maxMemory = this.maxMemory;
		return f;
	}

	public int getNodeCount() {
		return nodeCount;
	}

	public void setNodeCount(int nodeCount) {
		this.nodeCount = nodeCount;
	}

	public double getServerType() {
		return serverType;
	}

	public void setServerType(double serverType) {
		this.serverType = serverType;
	}

	public double getSwitchType() {
		return switchType;
	}

	public void setSwitchType(double switchType) {
		this.switchType = switchType;
	}

	public double getRouterType() {
		return routerType;
	}

	public void setRouterType(double routerType) {
		this.routerType = routerType;
	}

	public int getMinCpu() {
		return minCpu;
	}

	public void setMinCpu(int minCpu) {
		this.minCpu = minCpu;
	}

	public int getMaxCpu() {
		return maxCpu;
	}

	public void setMaxCpu(int maxCpu) {
		this.maxCpu = maxCpu;
	}

	public int getMinMemory() {
		return minMemory;
	}

	public void setMinMemory(int minMemory) {
		this.minMemory = minMemory;
	}

	public int getMaxMemory() {
		return maxMemory;
	}

	public void setMaxMemory(int maxMemory) {
		this.maxMemory = maxMemory;
	}

	public int getMinDiskSpace() {
		return minDiskSpace;
	}

	public void setMinDiskSpace(int minDiskSpace) {
		this.minDiskSpace = minDiskSpace;
	}

	public int getMaxDiskSpace() {
		return maxDiskSpace;
	}

	public void setMaxDiskSpace(int maxDiskSpace) {
		this.maxDiskSpace = maxDiskSpace;
	}
}
